home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
cpdir.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
6KB
|
266 lines
/* cpdir - copy directory Author: Erik Baalbergen */
/* Use "cpdir [-v] src dst" to make a copy dst of directory src.
Cpdir should behave like the UNIX shell command
(cd src; tar cf - .) | (mkdir dst; cd dst; tar xf -)
The -m "merge" flag enables you to copy into an existing directory.
The -s "similar" flag preserves the full mode, uid, gid and times.
The -v "verbose" flag enables you to see what's going on when running cpdir.
Work yet to be done:
- link checks, i.e. am I not overwriting a file/directory by itself?
Please report bugs and suggestions to erikb@cs.vu.nl
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#define MKDIR1 "/bin/mkdir"
#define MKDIR2 "/usr/bin/mkdir"
#define BUFSIZE 1024
#define PLEN 256
#define DIRSIZ 16
#define MAXLINKS 512
struct {
unsigned short ino;
unsigned short dev;
char *path;
} links[MAXLINKS];
int nlinks = 0;
char *prog;
int vflag = 0; /* verbose */
int mflag = 0; /* force */
int sflag = 0; /* similar */
char *strcpy();
char *malloc();
main(argc, argv)
char *argv[];
{
int rc = 0;
char *p, *s;
struct stat st;
prog = *argv++;
if ((p = *argv) && *p == '-') {
argv++;
argc--;
while (*++p) {
switch (*p) {
case 'v': vflag = 1; break;
case 'm': mflag = 1; break;
case 's': sflag = 1; break;
default:
fatal("illegal flag %s", p);
}
}
}
if (argc != 3) fatal("Usage: cpdir [-msv] source destination");
s = *argv++;
if (stat(s, &st) < 0) fatal("can't get file status of %s", s);
if ((st.st_mode & S_IFMT) != S_IFDIR) fatal("%s is not a directory", s);
cpdir(&st, s, *argv);
exit(0);
}
cpdir(sp, s, d)
struct stat *sp;
char *s, *d;
{
char spath[PLEN], dpath[PLEN];
char ent[DIRSIZ + 1];
register char *send = spath, *dend = dpath;
int fd, n;
struct stat st;
static first = 1;
static dev_t dev;
static ino_t ino;
if ((fd = open(s, O_RDONLY)) < 0) {
nonfatal("can't read directory %s", s);
return;
}
if (
mflag == 0
||
stat(d, &st) != 0
||
(st.st_mode & S_IFMT) != S_IFDIR
) {
make_dir(d);
if (sflag) similar(sp, d);
}
if (first) {
stat(d, &st);
dev = st.st_dev;
ino = st.st_ino;
first = 0;
}
if (sp->st_dev == dev && sp->st_ino == ino) {
nonfatal("%s skipped to avoid an endless loop", s);
return;
}
while (*send++ = *s++) {
}
while (*dend++ = *d++) {
}
send[-1] = '/';
dend[-1] = '/';
ent[DIRSIZ] = '\0';
while ((n = read(fd, ent, DIRSIZ)) == DIRSIZ) {
if (!((ent[0] == '\0' && ent[1] == '\0') || (ent[2] == '.') &&
(ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0'))
)) {
strcpy(send, ent + 2);
strcpy(dend, ent + 2);
if (stat(spath, &st) < 0)
fatal("can't get file status of %s", spath);
if ((st.st_mode & S_IFMT) != S_IFDIR && st.st_nlink > 1)
if (cplink(st, spath, dpath) == 1) continue;
switch (st.st_mode & S_IFMT) {
case S_IFDIR:
cpdir(&st, spath, dpath);
break;
case S_IFREG:
cp(&st, spath, dpath);
break;
default:
cpspec(&st, spath, dpath);
break;
}
}
}
close(fd);
if (n) fatal("error in reading directory %s", spath);
}
make_dir(s)
char *s;
{
int pid, status;
if (vflag) printf("mkdir %s\n", s);
if ((pid = fork()) == 0) {
execl(MKDIR1, "mkdir", s, (char *) 0);
execl(MKDIR2, "mkdir", s, (char *) 0);
fatal("can't execute %s or %s", MKDIR1, MKDIR2);
}
if (pid == -1) fatal("can't fork", prog);
wait(&status);
if (status) fatal("can't create %s", s);
}
cp(sp, s, d)
struct stat *sp;
char *s, *d;
{
char buf[BUFSIZE];
int sfd, dfd, n;
if (vflag) printf("cp %s %s\n", s, d);
if ((sfd = open(s, O_RDONLY)) < 0)
nonfatal("can't read %s", s);
else {
if ((dfd = creat(d, sp->st_mode & 0777)) < 0)
fatal("can't create %s", d);
while ((n = read(sfd, buf, BUFSIZE)) > 0)
if (write(dfd, buf, n) != n)
fatal("error in writing file %s", d);
close(sfd);
close(dfd);
if (n) fatal("error in reading file %s", s);
if (sflag) similar(sp, d);
}
}
similar(sp, d)
struct stat *sp;
char *d;
{
time_t timep[2];
chmod(d, sp->st_mode);
chown(d, sp->st_uid, sp->st_gid);
timep[0] = sp->st_atime;
timep[1] = sp->st_mtime;
utime(d, timep);
}
nonfatal(s, a)
char *s, *a;
{
fprintf(stderr, "%s: ", prog);
fprintf(stderr, s, a);
fprintf(stderr, "\n");
}
fatal(s, a)
char *s, *a;
{
nonfatal(s, a);
exit(1);
}
cpspec(sp, s, d)
struct stat *sp;
char *s, *d;
{
if (vflag) {
printf("copy special file %s to %s.", s, d);
printf(" Major/minor = %d/%d.",
sp->st_rdev >> 8, sp->st_rdev & 0177);
printf(" Mode = %o.\n", sp->st_mode);
}
if (mknod(d, sp->st_mode, sp->st_rdev, 0) < 0) {
perror("mknod");
nonfatal("Cannot create special file %s.\n", d);
}
if (sflag) similar(sp, d);
}
cplink(st, spath, dpath)
struct stat st;
char *spath, *dpath;
{
/* Handle files that are links. Returns 0 if file must be copied.
* Returns 1 if file has been successfully linked. */
int i;
int linkent;
linkent = -1;
for (i = 0; i < nlinks; i++) {
if (links[i].dev == st.st_dev
&& links[i].ino == st.st_ino)
linkent = i;
}
if (linkent >= 0) { /* It's already in the link table *//* we
* must have copied it earlier. So just link
* to the saved dest path. Don't copy it
* twice. */
if (vflag) printf("ln %s %s\n", links[linkent].path, dpath);
if (link(links[linkent].path, dpath) < 0)
fatal("Could not link to %s\n", dpath);
return(1); /* Don't try to copy it */
} else { /* Make an entry in the link table */
if (nlinks >= MAXLINKS) fatal("Too many links at %s\n", dpath);
links[nlinks].dev = st.st_dev;
links[nlinks].ino = st.st_ino;
links[nlinks].path = malloc(strlen(dpath) + 1);
if (links[nlinks].path == NULL)
fatal("No more memory at %s\n", dpath);
strcpy(links[nlinks].path, dpath);
nlinks++;
/* Go ahead and copy it the first time */
return(0);
}
}